package com.xinsoft.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.CusDeviceVo;
import com.xinsoft.mapper.CusDeviceMapper;
import com.xinsoft.service.*;
import com.xinsoft.utils.ExcelUtils;
import com.xinsoft.validator.ValidatorUtils;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author hsm
* @description 针对表【cus_device(设备表)】的数据库操作Service实现
* @createDate 2023-06-13 15:45:33
*/
@Service
public class CusDeviceServiceImpl extends ServiceImpl<CusDeviceMapper, CusDevice>
    implements CusDeviceService{

    @Resource
    public SysSupplierLinkmanService sysSupplierLinkmanService;
    @Resource
    public SysDictionaryService sysDictionaryService;
    @Resource
    public SysUserService sysUserService;
    @Resource
    public SysDeptService sysDeptService;
    @Resource
    public SysSupplierService sysSupplierService;
    @Resource
    public SysFileHisService sysFileHisService;
    @Resource
    public CusTestPointService cusTestPointService;

    @Override
    public IPage<CusDeviceVo> findPageListByParam(CusDevicePageParam param) {

        //分页
        Page<CusDeviceVo> page = new Page<CusDeviceVo>(param.getCurrentPage(), param.getPageSize());
        //查询分页
        IPage<CusDeviceVo> pageList = this.baseMapper.findListByParam(page, param);

        return pageList;
    }


    @Override
    public List<CusDeviceVo> findListByParam(CusDevicePageParam param) {

        //查询分页
        List<CusDeviceVo> list = this.baseMapper.findListByParam(param);

        return list;
    }


    @Override
    public List<CusDeviceNetWorkDTO> networkingDeviceList(CusDeviceNetWorkDTO cusDeviceNetWorkDTO) {
        return this.baseMapper.networkingDeviceList(cusDeviceNetWorkDTO);
    }

    @Override
    public Map<String, Integer> deviceStatusData() {
        Map<String, Integer> map = new HashMap<>();
        // 正常运行
        Integer runtimeData = this.baseMapper.selectCount(new QueryWrapper<CusDevice>().eq("use_status", Const.DEVICE_STATUS.NORMAL));
        map.put("NORMAL",runtimeData);
        // 带病运行
        Integer warning = this.baseMapper.selectCount(new QueryWrapper<CusDevice>().eq("use_status", Const.DEVICE_STATUS.WARNING));
        map.put("WARNING",warning);
        // 停机待修
        Integer wait = this.baseMapper.selectCount(new QueryWrapper<CusDevice>().eq("use_status", Const.DEVICE_STATUS.WAIT));
        map.put("WAIT",wait);
        // 停用报废
        Integer dead = this.baseMapper.selectCount(new QueryWrapper<CusDevice>().eq("use_status", Const.DEVICE_STATUS.DEAD));
        map.put("DEAD",dead);
        return map;
    }


    @Override
    public CusDevice addCusDevice(CusDevice cusDevice) {

        // 判断设备名称是否重复
        QueryWrapper<CusDevice> cusDeviceQuery1 = new QueryWrapper<>();
        cusDeviceQuery1.select("id");
        cusDeviceQuery1.eq("device_name",cusDevice.getDeviceName());
        List devices = this.list(cusDeviceQuery1);
        if(CollectionUtil.isNotEmpty(devices)){
            throw new BDException("操作失败，设备名称重复！");
        }

        // 判断设备编号是否重复
        QueryWrapper<CusDevice> cusDeviceQuery = new QueryWrapper<>();
        cusDeviceQuery.select("id");
        cusDeviceQuery.eq("device_no",cusDevice.getDeviceNo());
        devices = this.list(cusDeviceQuery);

        if(CollectionUtil.isNotEmpty(devices)){
            throw new BDException("操作失败，设备编号重复！");
        }
        save(cusDevice);

        return cusDevice;
    }

    @Override
    public CusDevice editCusDevice(CusDevice cusDevice) {
        // 判断设备名称是否重复
        QueryWrapper<CusDevice> cusDeviceQuery1 = new QueryWrapper<>();
        cusDeviceQuery1.select("id");
        cusDeviceQuery1.ne("id",cusDevice.getId());
        cusDeviceQuery1.eq("device_name",cusDevice.getDeviceName());
        List devices = this.list(cusDeviceQuery1);
        if(CollectionUtil.isNotEmpty(devices)){
            throw new BDException("操作失败，设备名称重复！");
        }

        // 判断设备编号是否重复
        QueryWrapper<CusDevice> cusDeviceQuery = new QueryWrapper<>();
        cusDeviceQuery.select("id");
        cusDeviceQuery.eq("device_no",cusDevice.getDeviceNo());
        cusDeviceQuery.ne("id",cusDevice.getId());
        devices = this.list(cusDeviceQuery);

        if(CollectionUtil.isNotEmpty(devices)){
            throw new BDException("操作失败，设备编号重复！");
        }
        updateById(cusDevice);
        return cusDevice;
    }

    @Override
    public void del(List<Integer> ids) {
        this.removeByIds(ids);
    }

    @Override
    public CusDeviceVo getCusDevice(Integer id) {
        CusDeviceVo cusDeviceVo = this.baseMapper.findDeviceInfo(id);
        if(cusDeviceVo==null){
            throw new BDException("获取失败，数据不存在！");
        }
        SysSupplierLinkman linkMan =  getSupplierLinkMan(cusDeviceVo.getFactoryId());
        cusDeviceVo.setFactoryLinkmanName(linkMan.getLinkmanName());
        cusDeviceVo.setFactoryLinkmanPhone(linkMan.getLinkmanPhone());

        linkMan =  getSupplierLinkMan(cusDeviceVo.getSupplierId());
        cusDeviceVo.setSupplierLinkmanName(linkMan.getLinkmanName());
        cusDeviceVo.setSupplierLinkmanPhone(linkMan.getLinkmanPhone());

        linkMan =  getSupplierLinkMan(cusDeviceVo.getServiceId());
        cusDeviceVo.setServiceLinkmanName(linkMan.getLinkmanName());
        cusDeviceVo.setServiceLinkmanPhone(linkMan.getLinkmanPhone());

        return cusDeviceVo;
    }

    private SysSupplierLinkman getSupplierLinkMan(Integer id){
        SysSupplierLinkman result = new SysSupplierLinkman();
        QueryWrapper<SysSupplierLinkman> sysSupplierLinkmanQueryWrapper = new QueryWrapper<>();
        sysSupplierLinkmanQueryWrapper.eq("supplier_id",id);
        List<SysSupplierLinkman> list = sysSupplierLinkmanService.list(sysSupplierLinkmanQueryWrapper);
        if(CollectionUtil.isNotEmpty(list)&&list.size()>0){
            result = list.get(0);
        }
        return result;
    }


    @Override
    public JSONObject importExcel(MultipartFile multipartFile) throws IOException {
        // 初始化错误行信息list，用来记录导入失败的rowNum
        List<ExcelErrRowDTO> errRowDOs = new ArrayList<>();

        // 对excel是否为空进行check
        if (multipartFile.isEmpty()) {
            throw new BDException("导入失败，请选择文件！");
        }

        //设置excel参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        List<CusDeviceImportDTO> cusDeviceList;
        List<CusDevice> cusDevices = CollectionUtil.newArrayList();

        // 解析excel中的行，cusDeviceList
        try {
            // 解析excel
            cusDeviceList = ExcelImportUtil.importExcel(multipartFile.getInputStream(), CusDeviceImportDTO.class, params);
        } catch (Exception e) {
            throw new BDException("导入失败，文件内容解析错误！");
        }
        JSONObject result = new JSONObject();

        //校验
        if (cusDeviceList.size() > 0) {
            //取出excel和db中所有重复的name

            //获取excel中所有的username
            List<String> excelDeviceNames = cusDeviceList.stream()
                    .map(CusDeviceImportDTO::getDeviceName)
                    .collect(Collectors.toList());
            //获取系统中所有的DeviceName
            List<String> dbDeviceNames = this.getAllDeviceName();
            // 存放存在重复的deviceName，用于定位重复存放存在重复的deviceName的行
            List<String> duplicateDeviceNames = new ArrayList<>();

            if (dbDeviceNames.size() > 0 && excelDeviceNames.size() > 0) {
                //合并
                dbDeviceNames.addAll(excelDeviceNames);
                //取出存在重复的username
                duplicateDeviceNames = ExcelUtils.getDuplicateElements(dbDeviceNames);
            }

            //取出excel和db中所有重复的deviceNo

            // 获取excel中所有的deviceNo
            List<String> excelDeviceNo = cusDeviceList.stream()
                    .map(CusDeviceImportDTO::getDeviceNo)
                    .collect(Collectors.toList());
            List<String> dbDeviceNo = this.getAllDeviceNo();//获取系统中所有的deviceNo
            List<String> duplicateDeviceNo = new ArrayList<>(); // 存放存在重复的Clientcode，用于定位重复存放存在重复的clientName的行

            if (dbDeviceNo.size() > 0 && excelDeviceNo.size() > 0) {
                dbDeviceNo.addAll(excelDeviceNo);//合并
                duplicateDeviceNo = ExcelUtils.getDuplicateElements(dbDeviceNo);//取出存在重复的username
            }

            // 设备类型（字典）device_type
            List<SysDictionary> deviceTypeList =  sysDictionaryService.getDictByTypeCode("device_type");
            Map<String, Integer> deviceTypeMap = deviceTypeList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 使用状况(字典 device_status)
            List<SysDictionary> useStatusList =  sysDictionaryService.getDictByTypeCode("device_status");
            Map<String, Integer> useStatusMap = useStatusList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 设备用途(字典 device_purpose)
            List<SysDictionary> deviceUseList =  sysDictionaryService.getDictByTypeCode("device_purpose");
            Map<String, Integer> deviceUseMap = deviceUseList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 设备来源(字典 device_source)
            List<SysDictionary> deviceSouceList =  sysDictionaryService.getDictByTypeCode("device_source");
            Map<String, Integer> deviceSouceMap = deviceSouceList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 部门
            List<SysDept> deptList = sysDeptService.list();
            Map<String, Integer> deptMap = deptList.stream()
                    .collect(Collectors.toMap(SysDept::getDeptName, SysDept::getId, (v1, v2) -> v2));

            // 人员
            List<SysUser> userList = sysUserService.list();
            Map<String, SysUser> userMap = userList.stream()
                    .collect(Collectors.toMap(SysUser::getRealName, Function.identity(), (v1, v2) -> v2));

            // 供应商
            List<SysSupplier> supplierList = sysSupplierService.list();
            Map<String, Integer> supplierMap = supplierList.stream()
                    .collect(Collectors.toMap(SysSupplier::getSupplierName, SysSupplier::getId, (v1, v2) -> v2));




            int index = 1;
            for (CusDeviceImportDTO cusDeviceDTO : cusDeviceList) {
                index ++;
                // check
                StringBuilder stringBuilder = new StringBuilder();
                ExcelErrRowDTO excelErrRowDO= new ExcelErrRowDTO();

                // 参数校验
                stringBuilder.append(ValidatorUtils.validateExcel(cusDeviceDTO));

                // 检验deviceName 是否重复
                if(duplicateDeviceNames.contains(cusDeviceDTO.getDeviceName())){
                    stringBuilder.append("设备名称已经存在，请勿重复！");
                }
                // 检验deviceNo 是否重复
                if(duplicateDeviceNo.contains(cusDeviceDTO.getDeviceNo())){
                    stringBuilder.append("设备编号已经存在，请勿重复！");
                }

                // 设备类型
                if(StringUtils.isNotEmpty(cusDeviceDTO.getDeviceTypeName())){
                    Integer typeId = deviceTypeMap.get(cusDeviceDTO.getDeviceTypeName());
                    if(typeId==null){
                        stringBuilder.append("设备类型:"+cusDeviceDTO.getDeviceTypeName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setDeviceType(typeId);
                }

                // 使用状况
                if(StringUtils.isNotEmpty(cusDeviceDTO.getUseStatusName())){
                    Integer useStatus = useStatusMap.get(cusDeviceDTO.getUseStatusName());
                    if(useStatus==null){
                        stringBuilder.append("使用状况:"+cusDeviceDTO.getUseStatusName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setUseStatus(useStatus);
                }

                // 设备用途
                if(StringUtils.isNotEmpty(cusDeviceDTO.getDeviceUseName())){
                    Integer deviceUse = deviceUseMap.get(cusDeviceDTO.getDeviceUseName());
                    if(deviceUse==null){
                        stringBuilder.append("设备用途:"+cusDeviceDTO.getDeviceUseName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setDeviceUse(deviceUse);
                }

                // 设备来源
                if(StringUtils.isNotEmpty(cusDeviceDTO.getDeviceSouceName())){
                    Integer deviceSouce = deviceSouceMap.get(cusDeviceDTO.getDeviceSouceName());
                    if(deviceSouce==null){
                        stringBuilder.append("设备来源:"+cusDeviceDTO.getDeviceSouceName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setDeviceSouce(deviceSouce);
                }

                // 部门
                if(StringUtils.isNotEmpty(cusDeviceDTO.getDeptName())){
                    Integer deptId = deptMap.get(cusDeviceDTO.getDeptName());
                    if(deptId==null){
                        stringBuilder.append("部门:"+cusDeviceDTO.getDeptName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setDeptId(deptId);
                }

                // 负责人ID
                if(StringUtils.isNotEmpty(cusDeviceDTO.getUserName())){
                    SysUser user = userMap.get(cusDeviceDTO.getUserName());
                    if(user==null){
                        stringBuilder.append("负责人:"+cusDeviceDTO.getUserName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setUserId(user.getId());
                }

                // 生产商
                if(StringUtils.isNotEmpty(cusDeviceDTO.getFactoryIdName())){
                    Integer factoryId = supplierMap.get(cusDeviceDTO.getFactoryIdName());
                    if(factoryId==null){
                        stringBuilder.append("生产商:"+cusDeviceDTO.getFactoryIdName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setFactoryId(factoryId);
                }

                // 供应商
                if(StringUtils.isNotEmpty(cusDeviceDTO.getSupplierName())){
                    Integer supplierId = supplierMap.get(cusDeviceDTO.getSupplierName());
                    if(supplierId==null){
                        stringBuilder.append("供应商:"+cusDeviceDTO.getSupplierName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setSupplierId(supplierId);
                }

                // 服务商
                if(StringUtils.isNotEmpty(cusDeviceDTO.getServiceName())){
                    Integer serviceId = supplierMap.get(cusDeviceDTO.getServiceName());
                    if(serviceId==null){
                        stringBuilder.append("供应商:"+cusDeviceDTO.getServiceName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setServiceId(serviceId);
                }

                // 维修责任人
                if(StringUtils.isNotEmpty(cusDeviceDTO.getRepaireUserName())){
                    SysUser user = userMap.get(cusDeviceDTO.getRepaireUserName());
                    if(user==null){
                        stringBuilder.append("维修责任人:"+cusDeviceDTO.getRepaireUserName()+",在系统中不存在！");
                    }
                    cusDeviceDTO.setRepaireUserId(user.getId());
                }

                // 是否联网 0:否，1:是
                if(StringUtils.equals(cusDeviceDTO.getDoNetTouchName(),"是")){
                    cusDeviceDTO.setDoNetTouch(1);
                }else{
                    cusDeviceDTO.setDoNetTouch(0);
                }

                // 将错误行信息保存到list
                String errMsg = stringBuilder.toString();
                if(StringUtils.isNotEmpty(errMsg)){
                    excelErrRowDO.setRowIndex(index);
                    excelErrRowDO.setErrMessage(errMsg);
                    errRowDOs.add(excelErrRowDO);
                    continue;
                }
                //保存
                CusDevice device = new CusDevice();
                BeanUtils.copyProperties(cusDeviceDTO,device);
                cusDevices.add(device);
            }
            //批量保存
            saveBatch(cusDevices);
            String errFileUrl = ExcelUtils.exportErrRows(errRowDOs,multipartFile,sysFileHisService);

            result.put("errFileUrl",errFileUrl);
            return result;
        }
        return result;
    }

    private List<String> getAllDeviceNo() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("device_no");
        List<CusDevice> list = this.list();
        List<String> codes = list.stream().map(CusDevice::getDeviceNo).collect(Collectors.toList());
        return codes;
    }

    private List<String> getAllDeviceName() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("device_name");
        List<CusDevice> list = this.list();
        List<String> names = list.stream().map(CusDevice::getDeviceName).collect(Collectors.toList());
        return names;
    }

    @Override
    public SysCountDTO deviceCount(){
        SysCountDTO result = new SysCountDTO();
        result.setName1("设备总数");
        result.setValue1(String.valueOf(this.count()));

        result.setName2("采集比例");
        QueryWrapper queryWrapper= new QueryWrapper();
        queryWrapper.groupBy("device_id");
        int count = cusTestPointService.count();
        BigDecimal s = BigDecimal.valueOf(count).divide(new BigDecimal(result.getValue1()),2,BigDecimal.ROUND_HALF_UP);
        String value2 = s.max(BigDecimal.valueOf(100)).toString() +"%";
        result.setValue2(value2);
        return result;
    }
}




